package com.docker.core.third.docker;

import com.docker.core.constant.ConfigConstant;
import com.docker.core.mvc.Remark;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientConfig;
import com.github.dockerjava.core.DockerClientImpl;
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Record;
import kit.docker.datetime.DateKit;
import kit.docker.exception.BaseException;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author ldl
 * @Create 2020/12/01 001 15:45
 */
public class BaseDocker {
    /**
     * 连接池 改为线程安全
     *
     * @Author: zhl
     * @Create: 2021/1/13 17:00
     **/
    private static Map<String, SelfDockerClient> clientPool = new ConcurrentHashMap<>();

    /**
     * @Param: []
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 14:40
     */
    @Remark("获取连接池")
    protected static Map<String, SelfDockerClient> getClientPool() {
        return clientPool;
    }

    /**
     * @Param: [clientKey]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 15:02
     */
    @Remark("获取连接对象")
    public static DockerClient getDockerClient(String clientKey) {
        SelfDockerClient selfDockerClient = clientPool.get(clientKey);
        if (StrKit.notNull(selfDockerClient)) {
            selfDockerClient.setLast_connect_time(DateKit.getNowTimestamp());
            clientPool.put(clientKey, selfDockerClient);
            return selfDockerClient.getDockerClient();
        }
        throw new BaseException("docker未连接");
    }

    /**
     * @Param: [clientKey]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 15:02
     */
    @Remark("获取自定义连接对象")
    protected static SelfDockerClient getSeflDockerClient(String clientKey) {
        SelfDockerClient selfDockerClient = clientPool.get(clientKey);
        if (StrKit.notNull(selfDockerClient)) {
            return selfDockerClient;
        }
        throw new BaseException("docker未连接");
    }

    /**
     * @Param: [dockerClient]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 15:02
     */
    @Remark("获取自定义连接对象")
    protected static SelfDockerClient getSeflDockerClient(DockerClient dockerClient) {
        for (SelfDockerClient selfDockerClient : clientPool.values()) {
            if (selfDockerClient.getDockerClient().equals(dockerClient)) {
                return selfDockerClient;
            }
        }
        throw new BaseException("docker未连接");
    }

    /**
     * @Param: [dockerClient]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 15:02
     */
    @Remark("获取连接键")
    protected static String getClientKey(DockerClient dockerClient) {
        for (String clientKey : clientPool.keySet()) {
            if (clientPool.get(clientKey).getDockerClient().equals(dockerClient)) {
                return clientKey;
            }
        }
        throw new BaseException("docker未连接");
    }

    /**
     * @Param: [dockerClient]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 15:03
     */
    @Remark("获取连接键")
    protected static String getClientKey(SelfDockerClient dockerClient) {
        for (String clientKey : clientPool.keySet()) {
            if (clientPool.get(clientKey).equals(dockerClient)) {
                return clientKey;
            }
        }
        return null;
    }

    /**
     * @Param: [clientKey]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 15:03
     */
    @Remark("刷新最后通讯时间")
    protected static void refreshTime(String clientKey) {
        SelfDockerClient selfDockerClient = clientPool.get(clientKey);
        if (!StrKit.notNull(selfDockerClient)) {
            return;
        }
        refreshTime(selfDockerClient, clientKey);
    }

    /**
     * @Param: [clientKey, selfDockerClient]
     * @return: TODO
     * @Author: ldl
     * @Create: 2021/01/12 012 09:25
     */
    @Remark("刷新最后通讯时间")
    private static void refreshTime(SelfDockerClient selfDockerClient, String clientKey) {
        selfDockerClient.setLast_connect_time(DateKit.getNowTimestamp());
        clientPool.put(clientKey, selfDockerClient);
    }

    /**
     * @Param: [clientKey]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 15:03
     */
    @Remark("刷新最后通讯时间")
    protected static void refreshTime(SelfDockerClient dockerClient) {
        String clientKey = getClientKey(dockerClient);
        if (StrKit.notBlank(clientKey)) {
            refreshTime(dockerClient, clientKey);
        }
    }

    /**
     * @Param: [clientKey]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 15:03
     */
    @Remark("获取最后通讯时间")
    protected static Long getTime(String clientKey) {
        return clientPool.get(clientKey).getLast_connect_time();
    }

    /**
     * @Param: [clientKey, docker]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 15:03
     */
    @Remark("连接docker")
    protected static boolean connectDocker(String clientKey, Record docker) {
        return StrKit.notNull(connectDocker2(clientKey, docker));
    }

    /**
     * @Param: [clientKey, docker]
     * @return: TODO
     * @Author: ldl
     * @Create: 2021/01/11 011 10:16
     */
    @Remark("连接docker")
    protected static DockerClient connectDocker2(String clientKey, Record docker) {
        if (StrKit.notNull(clientPool.get(clientKey))) {
            throw new BaseException("docker已连接");
        }
        try {
            DockerClientConfig config = clientConfig(docker);
            ApacheDockerHttpClient.Builder builder = new ApacheDockerHttpClient.Builder();
            builder.dockerHost(config.getDockerHost());
            builder.sslConfig(config.getSSLConfig());
            builder.maxConnections(StrKit.notNull(docker.getInt("max_connect")) ? docker.getInt("max_connect") : PropKit.getInt(ConfigConstant.DOCKER_MAX_CONNECT, 10));
            if (StrKit.notNull(config.getSSLConfig())) {
                builder.sslConfig(config.getSSLConfig());
            }
            ApacheDockerHttpClient httpClient = builder.build();
            DockerClient dockerClient = DockerClientImpl.getInstance(config, httpClient);
            clientPool.put(clientKey, new SelfDockerClient(DateKit.getNowTimestamp(), dockerClient));
            return dockerClient;
        } catch (Exception e) {
            e.printStackTrace();
        }
        throw new BaseException("docker连接失败");
    }

    /**
     * @Param: [docker]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 15:04
     */
    @Remark("加载配置")
    private static DockerClientConfig clientConfig(Record docker) {
        DefaultDockerClientConfig.Builder configBuilder = DefaultDockerClientConfig.createDefaultConfigBuilder();

        if ("0".equals(docker.getStr("connect_type"))) {
            configBuilder.withDockerTlsVerify(false);//http
        } else {
            configBuilder.withDockerTlsVerify(true);//https
        }
        configBuilder.withDockerHost("tcp://" + docker.getStr("docker_host") + ":" + docker.getStr("docker_port"));//连接宿主机上的docker的ip地址和端口号
        if (System.getProperty("os.name").toLowerCase().contains("windows")) {
            configBuilder.withDockerCertPath(docker.getStr("cert_path"));//放置连接docker密钥路径
        } else {
            //放置连接docker密钥路径
            configBuilder.withDockerCertPath(PathKit.getWebRootPath() + docker.getStr("cert_path"));
        }
        if (StrKit.notBlank(docker.getStr("config_path"))) {
            configBuilder.withDockerConfig(docker.getStr("config_path"));//放置docker配置的路径
        }
        if (StrKit.notBlank(docker.getStr("api_version"))) {
            configBuilder.withApiVersion(docker.getStr("api_version"));
        }
        if (StrKit.notBlank(docker.getStr("registry_url"))) {
            configBuilder.withRegistryUrl(docker.getStr("registry_url"));//docker注册地址
        }
        configBuilder.withRegistryUsername(null);
        if (StrKit.notBlank(docker.getStr("user_name"))) {
            configBuilder.withRegistryUsername(docker.getStr("user_name"));//注册docker用户名
        }
        if (StrKit.notBlank(docker.getStr("password"))) {
            configBuilder.withRegistryPassword(docker.getStr("password")); //注册docker用户密码
        }
        if (StrKit.notBlank(docker.getStr("email"))) {
            configBuilder.withRegistryEmail(docker.getStr("email")); //注册docker用户邮箱 默认
        }
        return configBuilder.build();
    }

    /**
     * @Param: [clientKey]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 15:04
     */
    @Remark("关闭指定连接")
    protected static boolean close(String clientKey) {
        try {
            getDockerClient(clientKey).close();
            clientPool.remove(clientKey);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * @Param: [clientKey]
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 15:04
     */
    @Remark("关闭指定连接")
    protected static boolean close(DockerClient dockerClient) {
        try {
            dockerClient.close();
            for (String clientKey : clientPool.keySet()) {
                if (clientPool.get(clientKey).getDockerClient().equals(dockerClient)) {
                    clientPool.remove(clientKey);
                    break;
                }
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * @Param: []
     * @return: TODO
     * @Author: ldl
     * @Create: 2020/12/03 003 15:06
     */
    @Remark("关闭全部连接")
    protected static boolean close() {
        for (String clientKey : clientPool.keySet()) {
            try {
                clientPool.get(clientKey).getDockerClient().close();
                clientPool.remove(clientKey);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

}
